#define BOOST_TEST_MODULE testChangesManager

#include <iostream>

#include <boost/test/unit_test.hpp>

#include "common/elements/element_type.hpp"
#include "common/more/uuid.h"

#include "datenaro/session/changes_manager.h"

BOOST_AUTO_TEST_CASE(testTemplateHelper01)
{
    ChangesManager changesManager;
    const auto sessionUuid = Uuids::newUuid();
    changesManager.addSession(sessionUuid);
    changesManager.push(Elements::ElementType::Edge, 1);
    changesManager.push(Elements::ElementType::Edge, 2);
    changesManager.push(Elements::ElementType::FieldType, 3);
    changesManager.push(Elements::ElementType::ItemType, 1);
    const auto changes = changesManager.pop(sessionUuid);
    BOOST_CHECK(!changes.empty());
    for (const auto& [type, ids] : changes)
    {
        switch (type)
        {
        case Elements::ElementType::Edge:
            BOOST_CHECK(2 == ids.size());
            BOOST_CHECK(ids.cend() != ids.find(1));
            BOOST_CHECK(ids.cend() != ids.find(2));
            BOOST_CHECK(ids.cend() == ids.find(3));
            break;
        case Elements::ElementType::FieldType:
            BOOST_CHECK(1 == ids.size());
            BOOST_CHECK(ids.cend() == ids.find(1));
            BOOST_CHECK(ids.cend() == ids.find(2));
            BOOST_CHECK(ids.cend() != ids.find(3));
            break;
        case Elements::ElementType::ItemType:
            BOOST_CHECK(1 == ids.size());
            BOOST_CHECK(ids.cend() != ids.find(1));
            BOOST_CHECK(ids.cend() == ids.find(2));
            BOOST_CHECK(ids.cend() == ids.find(3));
            break;
        default:
            BOOST_CHECK(false);
            break;
        }
    }
    changesManager.removeSession(sessionUuid);
}

BOOST_AUTO_TEST_CASE(testTemplateHelper02)
{
    ChangesManager changesManager;
    const auto sessionUuid1 = Uuids::newUuid();
    const auto sessionUuid2 = Uuids::newUuid();
    const auto sessionUuid3 = Uuids::newUuid();
    changesManager.addSession(sessionUuid1);
    changesManager.addSession(sessionUuid2);
    changesManager.addSession(sessionUuid3);
    changesManager.push(Elements::ElementType::Edge, 1);
    changesManager.push(Elements::ElementType::Edge, 2);
    changesManager.push(Elements::ElementType::FieldType, 3);
    changesManager.push(Elements::ElementType::ItemType, 1);

    auto checkChanges = [](const auto& changes)
    {
        BOOST_CHECK(!changes.empty());
        for (const auto& [type, ids] : changes)
        {
            switch (type)
            {
            case Elements::ElementType::Edge:
                BOOST_CHECK(2 == ids.size());
                BOOST_CHECK(ids.cend() != ids.find(1));
                BOOST_CHECK(ids.cend() != ids.find(2));
                BOOST_CHECK(ids.cend() == ids.find(3));
                break;
            case Elements::ElementType::FieldType:
                BOOST_CHECK(1 == ids.size());
                BOOST_CHECK(ids.cend() == ids.find(1));
                BOOST_CHECK(ids.cend() == ids.find(2));
                BOOST_CHECK(ids.cend() != ids.find(3));
                break;
            case Elements::ElementType::ItemType:
                BOOST_CHECK(1 == ids.size());
                BOOST_CHECK(ids.cend() != ids.find(1));
                BOOST_CHECK(ids.cend() == ids.find(2));
                BOOST_CHECK(ids.cend() == ids.find(3));
                break;
            default:
                BOOST_CHECK(false);
                break;
            }
        }
    };

    checkChanges(changesManager.pop(sessionUuid1));
    checkChanges(changesManager.pop(sessionUuid2));
    checkChanges(changesManager.pop(sessionUuid3));

    BOOST_CHECK(changesManager.pop(sessionUuid1).empty());
    BOOST_CHECK(changesManager.pop(sessionUuid2).empty());
    BOOST_CHECK(changesManager.pop(sessionUuid3).empty());

    changesManager.removeSession(sessionUuid3);
    changesManager.removeSession(sessionUuid2);
    changesManager.removeSession(sessionUuid1);
}

BOOST_AUTO_TEST_CASE(testTemplateHelper03)
{
    ChangesManager changesManager;
    const auto sessionUuid = Uuids::newUuid();
    changesManager.addSession(sessionUuid);
    changesManager.push(Elements::ElementType::Edge, 1);
    changesManager.push(Elements::ElementType::Edge, 2);
    changesManager.push(Elements::ElementType::FieldType, 3);
    changesManager.push(Elements::ElementType::ItemType, 1);

    changesManager.erase(sessionUuid, Elements::ElementType::Edge, { 1, 2, 3 });

    const auto changes = changesManager.pop(sessionUuid);
    BOOST_CHECK(!changes.empty());
    for (const auto& [type, ids] : changes)
    {
        switch (type)
        {
        case Elements::ElementType::FieldType:
            BOOST_CHECK(1 == ids.size());
            BOOST_CHECK(ids.cend() == ids.find(1));
            BOOST_CHECK(ids.cend() == ids.find(2));
            BOOST_CHECK(ids.cend() != ids.find(3));
            break;
        case Elements::ElementType::ItemType:
            BOOST_CHECK(1 == ids.size());
            BOOST_CHECK(ids.cend() != ids.find(1));
            BOOST_CHECK(ids.cend() == ids.find(2));
            BOOST_CHECK(ids.cend() == ids.find(3));
            break;
        default:
            BOOST_CHECK(false);
            break;
        }
    }

    changesManager.removeSession(sessionUuid);
}
